昨天pagination失敗,還沒有時間研讀Grail API相關參數以及如何設計controller,今天先介紹Grails對Ajax的支援以及template fragment在列表文章的應用,可以上GSP的程式碼更簡潔,在Grails在寫出Ajax網頁還需javascript的library支援例如jquery(Grails預設已安裝jquery),搭配Grails tag即可做出有Ajax功能的網頁,今天將以之前posthistory.gsp為例
關於Ajax,首先我們必須認識幾個Grails Tags
1.
<g:javascript library="jquery">javascript code</g:javascript>
就是import jquery這個library,跟html不同的是grails是用plugin管理,而html則是要給檔案位置,另外tag間沒意外地可以寫javascript
2.
<g:submitToRemote url="" update="", onSuccess="", onLoading="", onComplete=""/>
此Tag就是ajax版的<g:submit>只是多了很多參數,來指定包裝後的xmlhttpresponse相關參數 ,url參數要指定action由哪一個controller負責,update參數指的是由controller回傳回來的參數要放在哪裡,onSuccess指Ajax動作完成後作什麼事,onLoading代表還未收到回應時作什麼事情,其餘以此類推
再來是template fragment,本例是將allPost交由_postentries.gsp來顯示,要注意template fragment網頁命名時前面要加底線,然後在posthistory.gsp使用<g:render>則只要指定postentries,不需要加底線
_postentries.gsp code的內容相當容易理解,只是把之前寫在posthistory allPosts裡的<g:each>搬到_postentries.gsp而已,code如下
<div class="postEntry">
<div class="postText">${post.content}</div>
<div class="postDate">${post.dateCreated}/></div>
</div>
接下來接先po上Ajax版的 posthistory.gsp
<%@ page contentType="text/html;charset=UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
<g:javascript library="jquery" />
<g:javascript>
function clearPost(e) {
$('#postContent').text('');
}
function showSpinner(visible) {
if (visible) $('#spinner').show();
else $('#spinner').hide();
}
</g:javascript>
<title>All Posts for ${ user.userId }</title>
<div class="body">
<h3>
Hi!
${ user.userId }, what is in you mind right now?
</h3>
<g:if test="${flash.message}">
<font size=3 color=#3bb11d>
<strong>
<u> ${flash.message}</u>
</strong>
</font>
</g:if>
<p>
<g:form action="ajaxAdd">
<g:textArea id='postContent' name="content" rows="3" cols="100" />
<br/>
<g:submitToRemote value="Post"
url="[controller: 'post', action: 'addPostAjax']" update="allPosts"
onSuccess="clearPost(e)" onLoading="showSpinner(true)"
onComplete="showSpinner(false)" />
<g:img id="spinner" style="display: none" uri="/images/spinner.gif" />
</g:form>
</p>
<br />
<hr size=1 align=center width=100%>
<div class="allPosts">
<g:render template="postentries" collection="${ user.posts}" var="post"/>
</div>
</div>
<g:submitToRemote>指定由PostController中addPostAjax來處理Ajax的request,得到的post結果將update到allPosts,onSuccess時用javascript function clearPost(e)清除<g:textArea>, onLoading時show spinner.gif表示Ajax動作中讓user不至於以為網頁沒動作,onComplete時就把spinner image hide
接下來必須新增addPostAjax code如下:
def addPostAjax(String content) {
try {
def newPost = postService.createPost(session.user.userId, content)
//利用PostService新增一個post
def recentPosts = Post.findAllByUser(session.user,
[sort: "dateCreated", order: "desc", max: 20])
//搜尋所有該user所有的post並依時間排序
render template: "postentries", collection: recentPosts, var: "post"
//render template fragment並將recentPost即所有的Post當作變數傳回
} catch (PostException pe) {
render {
div(class:"errors", pe.message)
}//把錯誤訊息render到div class="errors"
}
}
run-app即可成功顯示網頁
Post in progress, spinner image show....